
from core.DataStruct import Sample, ColorantGroup, Formula
from core.DataHandler import DataHandler
from core.ColorCombine import ColorCombine
import xlrd
from PyQt5.QtCore import *
import math
import matplotlib.pyplot as plt

class TierManager(QObject):
    """
    中间层；
    """
    stdSmpSetSignal = pyqtSignal()
    dataSmpSetSignal = pyqtSignal()
    colorantSelectSignal = pyqtSignal()

    colorCombineFinished = pyqtSignal()
    colorCorrectFinished = pyqtSignal()

    def __init__(self, config):
        super(TierManager, self).__init__()
        self.cfg = config
        self.group = ColorantGroup("油漆")                                                  # 色浆组；
        self.dataHander = DataHandler(self.group, config)                                   # 数据操作子；
        self.stdSmp  = Sample()                                                             # 标样；
        self.formula = Formula()                                                            # 配方；
        self.formula.nComp = 4                                                              # 选取色浆数目；  默认4个； 第一个为白；
        self.colorCombine = ColorCombine(self.group, self.formula, config)                  # 配色；
        self.recipeSmp = Sample()                                                           # 配方样本；
        self.threadForColorCombine = QThread()
        self.threadForColorCorrect = QThread()
        self.fig = None

    ################################################################################################################
    # 标样文件， 光谱文件， 打样光谱文件， 色浆选择；
    ################################################################################################################
    def setDataFile(self, fileName):
        """
        获取所有的光谱数据；          在进行获取数据前， 先设置好， 不然会报错；
        :param fileName:
        :return:
        """
        self.dataHander.getDataFromExcel(fileName)
        self.dataSmpSetSignal.emit()

    def setStdSmp(self,fileName):
        """
        设置标样；
        :param fileName:
        :return:
        """
        data = xlrd.open_workbook(fileName)
        sheet = data.sheet_by_index(0)
        for j in range(31):
            self.stdSmp.ref[j] = sheet.cell_value(1, j + 1) * 0.01          # 默认标样在第一行；
        self.stdSmp.ref[31] = 2 * self.stdSmp.ref[30] - self.stdSmp.ref[29]
        self.colorCombine.setStandardSmp(self.stdSmp)
        self.stdSmpSetSignal.emit()

    def setRecipeSample(self, fileName):
        """
        打样样本导入；
        :param fileName:
        :return:
        """
        self.recipeSmp.loadSmp(fileName)

    def selectColorant(self, idxList, bEvaluate = False):
        """
        选择色浆；
        :param idxList:
        :return:
        """
        if len(idxList) != 3 and not bEvaluate:
            return False
        self.formula.nComp = len(idxList) + 1
        self.formula.colorantsComp[0].colorants = self.group.pureWhite
        for i in range(len(idxList)):
            self.formula.colorantsComp[i+1].colorants = self.group.colorants[idxList[i]]
        self.colorantSelectSignal.emit()
        return True


    ################################################################################################################
    # 配色， 修色， 计算色差， 绘图；
    ################################################################################################################
    def startColorCombine(self):
        """
        开始配色；  线程；
        """
        if not self.threadForColorCombine.isFinished():
            self.threadForColorCombine.exit()
        self.colorCombine.base = self.group.baseWhite
        self.colorCombine.moveToThread(self.threadForColorCombine)
        self.threadForColorCombine.started.connect(self.colorCombine.calcConcBySpider)
        self.threadForColorCombine.start()
        print("开始配色")

    def startColorCorrect(self, testConc):
        """
        开始修色；  线程；
        :param testConc:
        :return:
        """
        if not self.threadForColorCorrect.isFinished():
            self.threadForColorCorrect.exit()
        tmpSmp = self.calcDeltaE()
        deltaXYZ = [0] * 3
        for k in range(3):
            deltaXYZ[k] = self.stdSmp.xyz[k] - tmpSmp.xyz[k]
        self.colorCombine.deltaXYZ = deltaXYZ
        self.colorCombine.factor = [1] * 32
        self.colorCombine.base = self.group.baseWhite
        self.colorCombine.preRecipe = testConc
        self.colorCombine.moveToThread(self.threadForColorCorrect)
        self.threadForColorCorrect.started.connect(self.colorCombine.calcAddRecipeBySpider)
        self.threadForColorCorrect.start()

    def calcRef(self, testConc, base):
        """
        计算当前配方的现实光谱，  反算
        :param testConc:
        :param base:
        :return:
        """
        nConc = len(testConc)
        self.colorCombine.calcDeltaE(testConc, base)
        for k in range(1, nConc, 1):
            tmpConc = testConc[k] / sum(testConc) * 100
            if tmpConc == 0:
                continue
            self.formula.colorantsComp[k].colorants.calcKSBySw (tmpConc)  # 计算对应浓度的单位吸收系数和单位散射系数；    采用插值；

        for k in range(nConc):
            self.formula.colorantsComp[k].quality = testConc[k]
        self.formula.calcKByS()  # 混合计算公式， 得到K/S；
        self.formula.calcRint(self.group.K1)  # 计算无限厚情况下的反射率；
        self.formula.calcSDMix(self.group.pureWhite)  # 计算厚度参数；   这个得精度影响了最终的结果；
        for k in range(32):
            tmp1 = (base.ref[k] - self.formula.rint[k]) / (self.formula.rint[k] * self.formula.rint[k])
            try:
                tmpSD = math.pow(math.e, self.formula.SDMix[k] * (1 / self.formula.rint[k] - self.formula.rint[k]))
            except:
                pass
            tmp2 = (1 / self.formula.rint[k] - base.ref[k]) * tmpSD
            tmp3 = base.ref[k] - self.formula.rint[k] + tmp2
            self.formula.ref[k] = self.formula.rint[k] * (tmp1 + tmp2) / tmp3
        #self.formula.calcRef(self.group.K1, self.cfg)  # 反算背景下的总反射率

    def calcDeltaE(self):
        """
        计算当前配方与标样的色差；
        :return:
        """
        tmpSmp = Sample()
        tmpSmp.ref = self.recipeSmp.ref
        tmpSmp.calcDeltaE(self.stdSmp)
        return tmpSmp

    def plotRefCurve(self):
        """
        显示当前的标样， 配方理论样， 配方实际样的光谱对比图；
        :return:
        """
        self.fig = plt.figure(1, figsize=(8, 6)) ,
        x = range(400, 720, 10)
        plt.title("test")
        plt.xlim((400, 710))
        plt.ylim((0, 1))
        plt.plot(x, self.stdSmp.ref, linestyle='-', alpha=0.8, color='r')
        plt.plot(x, self.formula.ref, linestyle='-', alpha=0.8, color='g')
        plt.plot(x, self.recipeSmp.ref, linestyle='-', alpha=0.8, color='b')
        plt.show()